package com.pajk.user.util;

import java.io.*;
import java.net.URL;
import java.security.KeyStore;
import java.util.concurrent.ConcurrentHashMap;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

/**
 * User: haihua.chenhh
 * Date: 14-4-15
 * Time: 下午3:35
 */
public class HttpsUtil {
    private static final Logger                                        log              = LoggerFactory
                                                                                            .getLogger(HttpsUtil.class);
    //private static final ConcurrentHashMap<String, HttpsURLConnection> urlConnectionMap = new ConcurrentHashMap<String, HttpsURLConnection>();

    public static String invoke(String httpsUrl, String params, SSLSocketFactory sslSocketFactory) {
        HttpsURLConnection connection = createConnection(httpsUrl, sslSocketFactory);
        return invoke(connection, params);

    }

    public static String invoke(HttpsURLConnection connection, String params) {

        byte data[] = params.getBytes();
        OutputStream out = null;
        BufferedReader aReader = null;

        try {
            //connection.connect();
            out = connection.getOutputStream();
            out.write(data);

            InputStreamReader inReader = new InputStreamReader(connection.getInputStream(), "utf-8");
            aReader = new BufferedReader(inReader);
            StringBuilder sb = new StringBuilder();
            String aLine;
            while ((aLine = aReader.readLine()) != null)
                sb.append(aLine);
            aReader.close();
            return sb.toString();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (aReader != null) {
                try {
                    aReader.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            connection.disconnect();
        }

    }

    public static HttpsURLConnection createConnection(String httpsUrl,
                                                      SSLSocketFactory sslSocketFactory) {
        /*HttpsURLConnection connection = urlConnectionMap.get(httpsUrl);
        if (connection != null) {
            return connection;
        }*/
        try {
            URL url = new URL(httpsUrl);
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    log.info("URL Host: " + session.getPeerHost());
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            if (connection != null && sslSocketFactory != null) {
                connection.setSSLSocketFactory(sslSocketFactory);
            } else {
                log.error("can't build connection:" + httpsUrl);
                throw new RuntimeException("can't build connection:" + httpsUrl);
            }
            connection.setRequestProperty("Content-Type", "text/xml");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setConnectTimeout(60 * 1000);
            connection.setReadTimeout(60 * 1000);
            /*HttpsURLConnection connection1 = urlConnectionMap.putIfAbsent(httpsUrl, connection);
            if (connection1 != null) {
                connection.disconnect();
                return connection1;
            }*/
            return connection;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("url=" + httpsUrl + " connect fail!" + e.getMessage(), e);
        }
    }

    public static SSLSocketFactory getSSLSocketFactory(String keyStoreType, String keyPassword,
                                                       String keyStorePath, String trustPassword,
                                                       String trustStorePath) throws Exception {

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory
            .getDefaultAlgorithm());
        KeyStore keyStore = getKeyStore(keyStoreType, keyPassword, keyStorePath);
        keyManagerFactory.init(keyStore, keyPassword.toCharArray());

        TrustManagerFactory trustManagerFactory = TrustManagerFactory
            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        KeyStore trustStore = getTrustStore(trustPassword, trustStorePath);
        trustManagerFactory.init(trustStore);

        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);

        return ctx.getSocketFactory();
    }

    public static KeyStore getKeyStore(String keyStoreType, String password, String keyStorePath)
                                                                                                  throws Exception {
        KeyStore ks = KeyStore.getInstance(keyStoreType);
        InputStream is = null;
        try {
            ClassPathResource classPathResource = new ClassPathResource(keyStorePath);
            is = classPathResource.getInputStream();
            ks.load(is, password.toCharArray());
        } finally {
            if (is != null)
                is.close();
        }
        return ks;
    }

    public static KeyStore getTrustStore(String password, String keyStorePath) throws Exception {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream is = null;
        try {
            ClassPathResource classPathResource = new ClassPathResource(keyStorePath);
            is = classPathResource.getInputStream();
            ks.load(is, password.toCharArray());
        } finally {
            if (is != null)
                is.close();
        }
        return ks;
    }

    public void getHttpClient(String keyStoreType, String keyPassword,
                              String keyStorePath, String trustPassword,
                              String trustStorePath) throws Exception {


        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(getKeyStore(keyStoreType,keyPassword,
                        keyStorePath), keyPassword.toCharArray())
                .loadTrustMaterial(getTrustStore(trustPassword,
                        trustStorePath))
                .build();

        X509HostnameVerifier hv = new X509HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                log.info("URL Host: " + session.getPeerHost());
                return true;
            }

            public void verify(String host, SSLSocket ssl) throws IOException {
            }

            public void verify(String host, String[] cns, String[] subjectAlts)
                    throws SSLException {
            }

            public void verify(String host,
                               X509Certificate cert)
                    throws SSLException {
            }
        };


        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,hv);

        PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
                RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .register("https", sslsf)
                        .build());
        poolingmgr.setMaxTotal(20);

        SocketConfig sconfig = SocketConfig.custom().setSoTimeout(3*1000).build();

        poolingmgr.setDefaultSocketConfig(sconfig);

        CloseableHttpClient client = HttpClients.custom()
                .setConnectionManager(poolingmgr)
                .build();

        HttpPost post = new HttpPost(
                "https://eairiis-stgdmz.paic.com.cn/invoke/wm.tn/receive");

        HttpResponse response = client.execute(post);


        System.out.println(response.getStatusLine().getStatusCode());


    }
}
